#include "callback_dispatcher_impl.h"
#include "spdlog/spdlog.h"
#include <algorithm>

CallbackDispatcherImpl::CallbackDispatcherImpl() {}

void CallbackDispatcherImpl::registerCallback(std::shared_ptr<OrderCallback> callback) {
    std::unique_lock lock(callbacksMutex_);
    if (std::find(callbacks_.begin(), callbacks_.end(), callback) == callbacks_.end()) {
        callbacks_.push_back(callback);
        SPDLOG_DEBUG("Callback registered successfully");
    }
}

void CallbackDispatcherImpl::notifyOrderStatus(const Order& order, OrderStatus status) {
    if (isNotifying_.exchange(true)) {
        SPDLOG_WARN("Notification already in progress");
        return;
    }

    std::shared_lock lock(callbacksMutex_);
    auto localCallbacks = callbacks_; // Copy for thread safety
    
    lock.unlock();
    
    for (const auto& cb : localCallbacks) {
        try {
            cb->onOrderStatus(order, status);
        } catch (const std::exception& e) {
            SPDLOG_ERROR("OrderStatus callback failed: {}", e.what());
        }
    }
    
    isNotifying_.store(false);
}

void CallbackDispatcherImpl::notifyTrade(const Trade& trade) {
    if (isNotifying_.exchange(true)) {
        SPDLOG_WARN("Notification already in progress");
        return;
    }

    std::shared_lock lock(callbacksMutex_);
    auto localCallbacks = callbacks_;
    
    lock.unlock();
    
    for (const auto& cb : localCallbacks) {
        try {
            cb->onTrade(trade);
        } catch (const std::exception& e) {
            SPDLOG_ERROR("Trade callback failed: {}", e.what());
        }
    }
    
    isNotifying_.store(false);
}

void CallbackDispatcherImpl::notifyError(const OrderError& error) {
    if (isNotifying_.exchange(true)) {
        SPDLOG_WARN("Notification already in progress");
        return;
    }

    std::shared_lock lock(callbacksMutex_);
    auto localCallbacks = callbacks_;
    
    lock.unlock();
    
    for (const auto& cb : localCallbacks) {
        try {
            cb->onError(error);
        } catch (const std::exception& e) {
            SPDLOG_ERROR("Error callback failed: {}", e.what());
        }
    }
    
    isNotifying_.store(false);
}